"""
基于ADB命令的移动端驱动器
当uiautomator2无障碍服务无法使用时的替代方案
"""

import subprocess
import time
import logging
from typing import Optional, List, Dict, Tuple
import json
from utils.mobile_driver_base import MobileDriverBase


class AdbMobileDriver(MobileDriverBase):
    """基于ADB命令的移动端驱动器"""

    def __init__(self, config: dict):
        self.config = config
        self.device_id = None
        self.logger = self._setup_logger()

    def _setup_logger(self) -> logging.Logger:
        """设置日志记录器"""
        logger = logging.getLogger("AdbMobileDriver")
        if not logger.handlers:
            handler = logging.StreamHandler()
            formatter = logging.Formatter(
                "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
            )
            handler.setFormatter(formatter)
            logger.addHandler(handler)
            logger.setLevel(logging.INFO)
        return logger

    def init_device(self) -> None:
        """初始化设备连接"""
        try:
            # 获取设备列表
            result = subprocess.run(
                ["adb", "devices"], capture_output=True, text=True, timeout=10
            )

            if result.returncode != 0:
                raise RuntimeError("ADB命令不可用")

            devices = []
            for line in result.stdout.strip().splitlines()[1:]:
                if "device" in line and not "offline" in line:
                    device_id = line.split()[0]
                    devices.append(device_id)

            if not devices:
                raise RuntimeError("未检测到任何设备")

            self.device_id = devices[0]
            self.logger.info(f"已连接设备: {self.device_id}")

            # 获取设备信息
            info = self.get_device_info()
            self.logger.info(f"设备信息: {info.get('model', 'Unknown')}")

        except Exception as e:
            self.logger.error(f"设备初始化失败: {e}")
            raise

    def get_device_info(self) -> dict:
        """获取设备信息"""
        try:
            info = {}
            commands = {
                "model": "adb shell getprop ro.product.model",
                "brand": "adb shell getprop ro.product.brand",
                "version": "adb shell getprop ro.build.version.release",
            }

            for key, cmd in commands.items():
                result = subprocess.run(cmd.split(), capture_output=True, text=True)
                if result.returncode == 0:
                    info[key] = result.stdout.strip()

            return info
        except:
            return {}

    def start_app(self, package_name: Optional[str] = None) -> bool:
        """启动App"""
        try:
            if package_name is None:
                package_name = self.config.get("mobile", {}).get(
                    "app_package", "cn.damai"
                )

            self.logger.info(f"正在启动App: {package_name}")
            cmd = f"adb shell am start -n {package_name}/.MainActivity"
            result = subprocess.run(cmd.split(), timeout=10)

            if result.returncode == 0:
                time.sleep(3)  # 等待App启动
                return True
            else:
                # 尝试通用启动方法
                cmd = f"adb shell monkey -p {package_name} -c android.intent.category.LAUNCHER 1"
                result = subprocess.run(cmd.split(), timeout=10)
                time.sleep(3)
                return result.returncode == 0

        except Exception as e:
            self.logger.error(f"启动App失败: {e}")
            return False

    def stop_app(self, package_name: Optional[str] = None) -> bool:
        """停止App"""
        try:
            if package_name is None:
                package_name = self.config.get("mobile", {}).get(
                    "app_package", "cn.damai"
                )
            cmd = f"adb shell am force-stop {package_name}"
            result = subprocess.run(cmd.split(), timeout=10)
            return result.returncode == 0
        except Exception as e:
            self.logger.error(f"停止App失败: {e}")
            return False

    def click_text(self, text: str, timeout: int = 5) -> bool:
        """点击包含指定文本的元素（ADB实现较简单）"""
        try:
            # ADB无法直接通过文本点击，这里返回False
            # 实际使用时可以结合OCR或图像识别
            self.logger.warning(f"ADB驱动器不支持直接文本点击: {text}")
            return False
        except Exception as e:
            self.logger.error(f"点击文本失败: {e}")
            return False

    def wait_for_text(self, text: str, timeout: int = 10) -> bool:
        """等待文本出现（ADB实现较简单）"""
        try:
            # ADB无法直接检测文本，这里返回False
            # 实际使用时可以结合OCR或图像识别
            self.logger.warning(f"ADB驱动器不支持直接文本检测: {text}")
            return False
        except Exception as e:
            self.logger.error(f"等待文本失败: {e}")
            return False

    def click_coordinate(self, x: int, y: int) -> bool:
        """点击坐标"""
        try:
            cmd = f"adb shell input tap {x} {y}"
            result = subprocess.run(cmd.split(), timeout=5)
            time.sleep(0.5)
            return result.returncode == 0
        except Exception as e:
            self.logger.error(f"点击坐标失败: {e}")
            return False

    def input_text(self, text_content: str) -> bool:
        """输入文本"""
        try:
            # 替换特殊字符
            text_content = text_content.replace(" ", "%s")  # 空格
            cmd = f"adb shell input text '{text_content}'"
            result = subprocess.run(cmd, shell=True, timeout=10)
            time.sleep(0.5)
            return result.returncode == 0
        except Exception as e:
            self.logger.error(f"输入文本失败: {e}")
            return False

    def press_key(self, key: str) -> bool:
        """按键操作"""
        try:
            # 键名到键码的映射
            key_codes = {
                "BACK": 4,
                "HOME": 3,
                "enter": 66,
                "ENTER": 66,
                "UP": 19,
                "DOWN": 20,
                "LEFT": 21,
                "RIGHT": 22,
            }

            # 如果是数字，直接使用
            if key.isdigit():
                keycode = int(key)
            else:
                keycode = key_codes.get(key.upper(), 4)  # 默认返回键

            cmd = f"adb shell input keyevent {keycode}"
            result = subprocess.run(cmd.split(), timeout=5)
            time.sleep(0.3)
            return result.returncode == 0
        except Exception as e:
            self.logger.error(f"按键操作失败: {e}")
            return False

    def press_back(self) -> bool:
        """按返回键"""
        return self.press_key("BACK")

    def press_home(self) -> bool:
        """按Home键"""
        return self.press_key("HOME")

    def swipe_screen(
        self, start_x: int, start_y: int, end_x: int, end_y: int, duration: float = 0.5
    ) -> bool:
        """滑动操作"""
        try:
            duration_ms = int(duration * 1000)  # 转换为毫秒
            cmd = f"adb shell input swipe {start_x} {start_y} {end_x} {end_y} {duration_ms}"
            result = subprocess.run(cmd.split(), timeout=10)
            time.sleep(duration)
            return result.returncode == 0
        except Exception as e:
            self.logger.error(f"滑动操作失败: {e}")
            return False

    def screenshot(self, filename: Optional[str] = None) -> str:
        """截图"""
        try:
            if filename is None:
                filename = f"screenshot_{int(time.time())}.png"

            # 在设备上截图
            subprocess.run(
                ["adb", "shell", "screencap", "/sdcard/screenshot.png"], timeout=10
            )
            # 拉取到电脑
            subprocess.run(
                ["adb", "pull", "/sdcard/screenshot.png", filename], timeout=10
            )

            self.logger.info(f"截图已保存: {filename}")
            return filename
        except Exception as e:
            self.logger.error(f"截图失败: {e}")
            return ""

    def get_current_activity(self) -> str:
        """获取当前Activity"""
        try:
            cmd = (
                "adb shell dumpsys window windows | grep -E 'mCurrentFocus|mFocusedApp'"
            )
            result = subprocess.run(cmd, shell=True, capture_output=True, text=True)

            if result.returncode == 0:
                for line in result.stdout.splitlines():
                    if "mCurrentFocus" in line or "mFocusedApp" in line:
                        return line.strip()
            return ""
        except Exception as e:
            self.logger.error(f"获取当前Activity失败: {e}")
            return ""

    def find_text_and_click(self, text: str) -> bool:
        """查找文本并点击（使用UI dump）"""
        try:
            # 获取UI层次结构
            subprocess.run(
                ["adb", "shell", "uiautomator", "dump", "/sdcard/ui.xml"], timeout=10
            )
            subprocess.run(["adb", "pull", "/sdcard/ui.xml", "ui.xml"], timeout=10)

            # 解析XML查找文本
            import xml.etree.ElementTree as ET

            tree = ET.parse("ui.xml")
            root = tree.getroot()

            for node in root.iter():
                node_text = node.get("text", "")
                if text in node_text:
                    bounds = node.get("bounds")
                    if bounds:
                        # 解析bounds="[x1,y1][x2,y2]"
                        bounds = bounds.replace("[", "").replace("]", ",").split(",")
                        if len(bounds) >= 4:
                            x = (int(bounds[0]) + int(bounds[2])) // 2
                            y = (int(bounds[1]) + int(bounds[3])) // 2
                            self.logger.info(f"找到文本'{text}'，点击坐标({x}, {y})")
                            return self.click_coordinate(x, y)

            self.logger.warning(f"未找到文本: {text}")
            return False

        except Exception as e:
            self.logger.error(f"查找文本并点击失败: {e}")
            return False

    def close_device(self) -> None:
        """关闭设备连接"""
        self.logger.info("ADB驱动器资源清理完成")


# 兼容性包装器，使其可以替代原来的MobileDriver
class MobileDriver(AdbMobileDriver):
    """兼容性包装器"""

    def find_element(self, **kwargs) -> bool:
        """查找元素（简化版）"""
        if "text" in kwargs:
            return self.find_text_and_click(kwargs["text"])
        elif "textContains" in kwargs:
            return self.find_text_and_click(kwargs["textContains"])
        else:
            self.logger.warning(f"不支持的查找条件: {kwargs}")
            return False

    def click_element(self, timeout: int = 10, **kwargs) -> bool:
        """点击元素"""
        return self.find_element(**kwargs)

    def wait_for_element(self, timeout: int = 10, **kwargs) -> bool:
        """等待元素出现"""
        if "text" in kwargs:
            return self.wait_for_text(kwargs["text"], timeout)
        elif "textContains" in kwargs:
            return self.wait_for_text(kwargs["textContains"], timeout)
        return False

    def tap_coordinate(self, x: int, y: int) -> None:
        """点击坐标（兼容接口）"""
        self.click_coordinate(x, y)

    def get_text(self, **kwargs) -> str:
        """获取元素文本（简化版）"""
        # ADB方式下较难实现，返回空字符串
        return ""

    def is_app_running(self, package_name: Optional[str] = None) -> bool:
        """检查App是否运行"""
        try:
            if package_name is None:
                package_name = self.config.get("mobile", {}).get(
                    "app_package", "cn.damai"
                )

            cmd = f"adb shell ps | grep {package_name}"
            result = subprocess.run(cmd, shell=True, capture_output=True, text=True)
            return package_name in result.stdout if package_name else False
        except:
            return False
